﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Configuration;
using System.Threading;
using System.IO;

namespace Communication
{
    public class HSSerialPort : IDisposable, IHSSerialPort
    {
        //流结尾
        private int endOfStream = -1;
        //结束字符
        private int endCharCode;
        //锁
        private object mutex = new object();
        //是否被检测
        private bool isChecked = false;
        //端口
        private SerialPort port = null;
        //接收到的内容
        private List<int> buffer = new List<int>();
        //当前使用的编码字符集
        private Encoding encodingDefault = default(Encoding);
        //数据接收完成后，触发事件
        public event ReceiveCompleted OnReceivedCompleted;

        //当前使用的编码字符集
        public Encoding Default
        {
            get { return encodingDefault; }
        }

        //不支持UTF-7编码
        public HSSerialPort(Encoding encoding, int endCharCode, string portName, int baudRate)
        {
            port = new SerialPort();

            this.endCharCode = endCharCode;
            this.encodingDefault = encoding;

            port.Encoding = encoding;
            port.PortName = portName;
            port.BaudRate = baudRate;
            port.DataReceived += DataReceived;
        }
        //当有数据到达缓存区后，触发事件
        private void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (!isChecked)
            {
                lock (mutex)
                {
                    if (!isChecked)
                    {
                        isChecked = true;
                        CheckReceivedIsCompleted();
                    }
                }
            }

        }

        private const int DELAY = 500;
        private const int ZERO = 0;
        //检查数据是否传输完成，根据终结字符判断
        private void CheckReceivedIsCompleted()
        {
            try
            {
                if (buffer.Count != 0) buffer.Clear();
                Thread.Sleep(DELAY);
                while (true)
                {
                    int lastCharCode = port.ReadByte();
                    if (lastCharCode != endCharCode)
                    {
                        buffer.Add(lastCharCode);
                        continue;
                    }
                    else if (lastCharCode == endCharCode)
                    {
                        isChecked = false;
                        buffer.Add(lastCharCode);
                        ReceivedIsCompleted();
                        return;
                    }

                }
            }
            catch (InvalidOperationException invalidEx)
            {

            }
            catch (ArgumentNullException arNullEx)
            {
                throw arNullEx;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //数据接收完成后，触发OnReceivedCompleted事件
        private void ReceivedIsCompleted()
        {
            ClearInBuffer();
            ReceiveCompleted temp = OnReceivedCompleted;
            if (temp != null)
            {
                temp.Invoke(buffer);
            }
        }

        public void Send(byte[] value)
        {
            try
            {
                port.Write(value, 0, value.Length);
            }
            catch (InvalidOperationException invalidEx)
            {
                throw invalidEx;
            }
            catch (ArgumentNullException arNullEx)
            {
                throw arNullEx;
            }
            catch (TimeoutException timeOutEx)
            {
                throw timeOutEx;
            }
        }

        public void Open()
        {
            try
            {
                port.Open();
            }
            catch (UnauthorizedAccessException uex)
            {
                throw new ComPortException(uex.Message);
            }
            catch (ArgumentOutOfRangeException aex)
            {
                throw new ComPortException(aex.Message);
            }
            catch (ArgumentException arex)
            {
                throw new ComPortException(arex.Message);
            }
            catch (IOException ioex)
            {
                throw new ComPortException(ioex.Message);
            }
            catch (InvalidOperationException inex)
            {
                throw new ComPortException(inex.Message);
            }
        }

        public void Close()
        {
            try
            {
                port.Close();
            }
            catch (IOException ioex)
            {
                throw new ComPortException(ioex.Message);
            }
        }

        public void Dispose()
        {
            if (port != null && port.IsOpen)
            {
                port.Close();
            }
        }


        public void ClearInBuffer()
        {
            port.DiscardInBuffer();
        }


        public void ReConnection(string portName, int baudRate)
        {
            port.Close();
            port.PortName = portName;
            port.BaudRate = baudRate;
            this.Open();
        }
    }
}
